package com.android.lovely.api.manager

import android.content.Context
import android.os.Build
import android.provider.Settings
import android.telephony.TelephonyManager
import android.text.format.DateUtils
import android.util.Base64
import android.util.Log
import com.android.lovely.BuildConfig
import com.android.lovely.api.encrypt.encryptAES
import com.android.lovely.api.logging.LoggingInterceptor
import com.android.lovely.api.ms.MoshiConverterFactory
import com.android.lovely.ext.isVPNConnected
import com.android.lovely.manager.KVStore
import com.android.lovely.user.UserManager
import com.kotlin.extensions.appContext
import com.kotlin.extensions.json.JsonExt.defaultMoshiBuilder
import com.kotlin.extensions.json.JsonExt.toJson
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import okhttp3.FormBody
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okio.Buffer
import retrofit2.Retrofit
import retrofit2.create
import java.io.IOException
import java.util.TimeZone
import java.util.concurrent.TimeUnit
import kotlin.text.Charsets.UTF_8

/**
 *
 * @author why
 * @date 2025/3/7 16:52
 */
inline fun httpLog(msg: String, exception: Throwable? = null) {
    Log.d("HttpLog", msg, exception)
}

val netWorkChangeState = MutableSharedFlow<Int>(0, 1, BufferOverflow.DROP_OLDEST)

var contactUrl: String = ""

object HttpManager {

    inline fun <reified T> createApi(): T {
        val client = OkHttpClient.Builder().retryOnConnectionFailure(false)
            .connectTimeout(150_000L, TimeUnit.MILLISECONDS)
            .readTimeout(150_000L, TimeUnit.MILLISECONDS)
            .writeTimeout(150_000L, TimeUnit.MILLISECONDS).addInterceptor(RequestInterceptor())
        if (BuildConfig.DEBUG) {
            client.addInterceptor(LoggingInterceptor())
        }
        return Retrofit.Builder().baseUrl(BuildConfig.API_HOST).client(client.build())
            .addConverterFactory(MoshiConverterFactory.create(defaultMoshiBuilder)).build().create()
    }

    inline fun <reified T> createGenerateApi(): T {
        val client = OkHttpClient.Builder().retryOnConnectionFailure(false)
            .connectTimeout(150_000L, TimeUnit.MILLISECONDS)
            .readTimeout(150_000L, TimeUnit.MILLISECONDS)
            .writeTimeout(150_000L, TimeUnit.MILLISECONDS).addInterceptor(GenerateInterceptor())
        if (BuildConfig.DEBUG) {
            client.addInterceptor(LoggingInterceptor())
        }
        return Retrofit.Builder().baseUrl(BuildConfig.API_HOST).client(client.build())
            .addConverterFactory(MoshiConverterFactory.create(defaultMoshiBuilder)).build().create()
    }

    class GenerateInterceptor : Interceptor {
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain): Response {
            val request = chain.request()
            val builder = request.newBuilder()
            builder.addHeader("access-token", UserManager.token)
            builder.addHeader(
                "d-id",
                Settings.Secure.getString(appContext.contentResolver, Settings.Secure.ANDROID_ID)
            )
            builder.addHeader("version", BuildConfig.VERSION_NAME)
            builder.addHeader("app-name", BuildConfig.APP_CODE)
            builder.addHeader("lang", KVStore.speakLanguage.code)
            builder.addHeader(
                "sim_country",
                (appContext.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager)?.simCountryIso.orEmpty()
            )
            builder.addHeader("is_vpn", (if (isVPNConnected()) 1 else 0).toString())
            builder.addHeader("d_model", Build.MODEL)
            builder.addHeader("sys_version", Build.VERSION.RELEASE)
            builder.addHeader(
                "timezone",
                "GMT${(TimeZone.getDefault().rawOffset / DateUtils.HOUR_IN_MILLIS).let { if (it >= 0) "+$it" else "$it" }}"
            )
            return chain.proceed(builder.build())
        }
    }

    class RequestInterceptor : Interceptor {
        override fun intercept(chain: Interceptor.Chain): Response {
            val originalRequest = chain.request()
            if (originalRequest.method == "POST") {
                if (originalRequest.body != null && originalRequest.body is FormBody) {
                    return chain.proceed(originalRequest)
                }
                if (originalRequest.body != null && originalRequest.body is MultipartBody) {
                    return chain.proceed(originalRequest)
                }
                val params = mutableMapOf<String, Any?>()
                val headerJson = mutableMapOf<String, Any>().apply {
                    put("access-token", UserManager.token)
                    put("d-id", (Settings.Secure.getString(appContext.contentResolver, Settings.Secure.ANDROID_ID)))
                    put("version", BuildConfig.VERSION_NAME)
                    put("app-name", BuildConfig.APP_CODE)
                    put("lang", KVStore.speakLanguage.code)
                    put(
                        "sim_country",
                        (appContext.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager)?.simCountryIso.orEmpty()
                    )
                    put("is_vpn", if (isVPNConnected()) 1 else 0)
                    put("d_model", Build.MODEL)
                    put("sys_version", Build.VERSION.RELEASE)
                    put(
                        "timezone",
                        "GMT${(TimeZone.getDefault().rawOffset / DateUtils.HOUR_IN_MILLIS).let { if (it >= 0) "+$it" else "$it" }}"
                    )
                }
                params["header"] = headerJson
                val buffer = Buffer()
                originalRequest.body?.writeTo(buffer)
                params["param"] = buffer.readString(UTF_8).ifEmpty { "{}" }
                val encrypt = params.toJson().encryptAES()
                val requestBody = mapOf(
                    "data" to Base64.encodeToString(
                        encrypt.toByteArray(), Base64.NO_WRAP
                    )
                ).toJson().toRequestBody("application/json".toMediaType())
                val newRequest =
                    originalRequest.newBuilder().method(originalRequest.method, requestBody).build()
                return chain.proceed(newRequest)
            }
            return chain.proceed(originalRequest)
        }
    }
}
